package com.huitone.smspfm.interfacz.mt;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.springframework.data.redis.connection.RedisConnection;

import com.bin.common.utils.DateTimeUtils;
import com.bin.common.utils.MD5Util;
import com.bin.common.utils.StringUtils;
import com.huitone.smspfm.interfacz.core.AppStaticConfigs;
import com.huitone.smspfm.interfacz.logger.ExtLogger;
import com.huitone.smspfm.context.utils.ContextPropertiesUtils;
import com.huitone.smspfm.interfacz.model.MessageSbt;
import com.huitone.smspfm.redis.model.AppCanstant;
import com.huitone.smspfm.redis.pipeline.PipelineOpts.ABExcuteCommands;
import com.huitone.smspfm.socket.core.handler.DefaultMessageHandler;
import com.huitone.smspfm.socket.core.net.ExtSocket;
import com.huitone.smspfm.socket.protocol.sgip.constant.ErrorCode;
import com.huitone.smspfm.socket.protocol.sgip.message.msgbody.Submit;
import com.huitone.smspfm.socket.protocol.sgip.message.msgbody.Submit2;
import com.huitone.smspfm.socket.protocol.sgip.message.msghead.Head;

/**   
* @Title SocketServerMessageHandler.java 
* @Package com.huitone.smspfm.interfacz.core 
* @Description TODO(用一句话描述该文件做什么) 
* @author ybliang   
* @date 2017年3月27日 下午3:18:53 
* @version V1.0   
*/
public class MtMessageHandler2 extends DefaultMessageHandler {

	private static final ExtLogger logger = ExtLogger.create(MtMessageHandler2.class);
	
	private String iSMCache = ContextPropertiesUtils.getProperty("SMCache");
	private byte[] iSMCacheB = AppStaticConfigs.stringRedisSerializer.serialize(iSMCache);
	
	private String iSMCacheHashPrefix = ContextPropertiesUtils.getProperty("SMCacheHashPrefix");
	
	private String smspfmModuleName = ContextPropertiesUtils.getProperty("smspfm.module.name");
	
	private static final String CurrAcceptSpeedS = "CurrAcceptSpeedS";
	private static final String CurrAcceptSpeedM = "CurrAcceptSpeedM";
	
	private static final byte[] CURR_ACCEPT_SPEEDS_B = AppStaticConfigs.stringRedisSerializer.serialize(CurrAcceptSpeedS);
	
	private static final byte[] CURR_ACCEPT_SPEEDM_B = AppStaticConfigs.stringRedisSerializer.serialize(CurrAcceptSpeedM);
	
	private byte[] currAcceptSpeedS_List = AppStaticConfigs.stringRedisSerializer.serialize(AppStaticConfigs.RunningParamsHash + ":" + CurrAcceptSpeedS);
	private byte[] currAcceptSpeedM_List = AppStaticConfigs.stringRedisSerializer.serialize(AppStaticConfigs.RunningParamsHash + ":" + CurrAcceptSpeedM);
	
	private long currSpeedS = 0;
	
	private long currSpeedM = 0;
	
	private final Object slock = new Object();
	
	private final Object mlock = new Object();
	
	private SocketServerArrayBlockingQueue sbt1Msg = new SocketServerArrayBlockingQueue(1000);
	private SocketServerArrayBlockingQueue sbt2Msg = new SocketServerArrayBlockingQueue(1000);
	
	private ArrayBlockingQueue<Map<byte[],byte[]>> speeds = new ArrayBlockingQueue<Map<byte[],byte[]>>(1000);
	
	private SeqRepeatFilterQueue filterQueue = new SeqRepeatFilterQueue();
	
	private ExecutorService executorService = new ThreadPoolExecutor(AppStaticConfigs.smspfmMhePoolSize, 
			AppStaticConfigs.smspfmMhePoolSize, 1L, TimeUnit.MINUTES, new ArrayBlockingQueue<>(1000), new RejectedExecutionHandler() {
		
		@Override
		public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
			boolean offer = false;
			while(!executor.isShutdown() && !offer) {
				offer = executor.getQueue().offer(r);
				if (!offer) {
					try {
						TimeUnit.MILLISECONDS.sleep(10);
					} catch (InterruptedException e) {}
				}
			}
		}
	});
	
	private ExecutorService executorSaveService = new ThreadPoolExecutor(10, 
			10, 1L, TimeUnit.MINUTES, new ArrayBlockingQueue<>(100), new RejectedExecutionHandler() {
		
		@Override
		public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
			boolean offer = false;
			while(!executor.isShutdown() && !offer) {
				offer = executor.getQueue().offer(r);
				if (!offer) {
					try {
						TimeUnit.MILLISECONDS.sleep(10);
					} catch (InterruptedException e) {}
				}
			}
		}
	});
	
	public MtMessageHandler2() {
		
		if (AppStaticConfigs.speedStatisticsOn) {
			
			startUpdateSpeedTasks();
			
			startSpeedWriteTasks();
			
		}
		
		saveSbt1();
		
		saveSbt2();
	}
	
	private final void saveSbt2() {
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				while ((executorService != null && !executorService.isShutdown()) || sbt2Msg.getSize() > 0) {
					
					List<MessageSbt> list = sbt2Msg.poll();
					
					if (list != null && !list.isEmpty()) {
						
						executorSaveService.submit(new Runnable() {
							
							@Override
							public void run() {
								
								List<String> serialnos = new ArrayList<>();
								
								AppStaticConfigs.pipelineOpts.save(new ABExcuteCommands() {
									
									@Override
									public void excute(RedisConnection connection) {
										
										List<byte[]> seqNums = new ArrayList<byte[]>();
										
										for (int i = 0 ; i < list.size() ; i ++) {
											
											MessageSbt msg = list.get(i);
											
											Head head = (Head) msg.getHead();
											Submit2 body = (Submit2) msg.getBody();
											
											String recvTime = DateTimeUtils.dateToStr(msg.getRecvTime(), "yyyyMMddHHmmss");
											String sendPort = StringUtils.substring(body.getSendPort(), 5); // 剔除端口号(固定前五位),保留扩展码
													//body.getSendPort();
											
											Map<byte[],byte[]> map = new HashMap<>();
											
											map.put(AppCanstant.SmsEntity.Srv_node, AppStaticConfigs.stringRedisSerializer.serialize(body.getSrvNode()));
											map.put(AppCanstant.SmsEntity.ServiceCode,  AppStaticConfigs.stringRedisSerializer.serialize(body.getServiceCode()));
											map.put(AppCanstant.SmsEntity.SmType,  AppStaticConfigs.stringRedisSerializer.serialize("1"));
											map.put(AppCanstant.SmsEntity.User,  AppStaticConfigs.stringRedisSerializer.serialize(body.getUserNumber()));
											map.put(AppCanstant.SmsEntity.Smcont,  AppStaticConfigs.stringRedisSerializer.serialize(body.getMsgContent()));
											map.put(AppCanstant.SmsEntity.Reportflag,  AppStaticConfigs.stringRedisSerializer.serialize(StringUtils.toString(body.getReportFlag())));
											map.put(AppCanstant.SmsEntity.recvTime,  AppStaticConfigs.stringRedisSerializer.serialize(recvTime));
											map.put(AppCanstant.SmsEntity.RecvModuleName,  AppStaticConfigs.stringRedisSerializer.serialize(smspfmModuleName));
											map.put(AppCanstant.SmsEntity.SendPort,  AppStaticConfigs.stringRedisSerializer.serialize(sendPort)); 
											map.put(AppCanstant.SmsEntity.SerialSegment,  AppStaticConfigs.stringRedisSerializer.serialize(head.getSerialNoPart1() + "," + head.getSerialNoPart2() + "," + head.getSerialNoPart3()));
											map.put(AppCanstant.SmsEntity.OrgSerialNo,  AppStaticConfigs.stringRedisSerializer.serialize(body.getOrgSerialNo()));
											map.put(AppCanstant.SmsEntity.OrgSrvNode,  AppStaticConfigs.stringRedisSerializer.serialize(body.getOrgSrvNode()));
											map.put(AppCanstant.SmsEntity.SendFeedbackResult, AppStaticConfigs.stringRedisSerializer.serialize("0"));
											
											String serialNo = head.getSerialNo();
											String userNumber = body.getUserNumber();
											
											String sequn = serialNo + ":" + userNumber;
											
											connection.hMSet(AppStaticConfigs.stringRedisSerializer.serialize(iSMCacheHashPrefix + ":" + sequn), map);
											//connection.lPush(iSMCacheB, AppStaticConfigs.stringRedisSerializer.serialize(sequn));
											//connection.zAdd(AppStaticConfigs.iRptRecvSerialsZSetB, System.currentTimeMillis(), AppStaticConfigs.stringRedisSerializer.serialize(msg.getEncodeSerialNo()));
											seqNums.add(AppStaticConfigs.stringRedisSerializer.serialize(sequn));
											
											serialnos.add(serialNo);
										}
										
										connection.lPush(iSMCacheB, seqNums.toArray(new byte[1][]));
									}

									@Override
									public void excuteCallback(List<Object> results) {
										logger.acceptd(serialnos.size() + " saved " + serialnos.toString());
									}
								});
							}
						});
					} else {
						try {
							TimeUnit.MILLISECONDS.sleep(100);
						} catch (InterruptedException e) {}
					}
				}
			}
		}).start();
	}
	
	private final void saveSbt1() {
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				while ((executorService != null && !executorService.isShutdown()) || sbt1Msg.getSize() > 0) {
					
					List<MessageSbt> list = sbt1Msg.poll();
					
					if (list != null && !list.isEmpty()) {
						
						executorSaveService.submit(new Runnable() {
							
							@Override
							public void run() {
								
								List<String> serialnos = new ArrayList<>();
								
								AppStaticConfigs.pipelineOpts.save(new ABExcuteCommands() {
									
									@Override
									public void excute(RedisConnection connection) {
										
										List<byte[]> seqNums = new ArrayList<byte[]>();
										
										for (int i = 0 ; i < list.size() ; i ++) {
											
											MessageSbt msg = list.get(i);
											
											Head head = (Head) msg.getHead();
											Submit body = (Submit) msg.getBody();
											
											String recvTime = DateTimeUtils.dateToStr(msg.getRecvTime(), "yyyyMMddHHmmss");
											String serialNo = head.getSerialNo();
											
											Set<String> userNumber = body.getUserNumber();
											for (String un:userNumber) {
												
												Map<byte[],byte[]> map = new HashMap<>();
												
												map.put(AppCanstant.SmsEntity.Srv_node, AppStaticConfigs.stringRedisSerializer.serialize(StringUtils.toString(body.getSrvNode())));
												map.put(AppCanstant.SmsEntity.ServiceCode, AppStaticConfigs.stringRedisSerializer.serialize(StringUtils.toString(body.getServiceCode())));
												map.put(AppCanstant.SmsEntity.SmType, AppStaticConfigs.stringRedisSerializer.serialize(StringUtils.toString(1)));
												map.put(AppCanstant.SmsEntity.User, AppStaticConfigs.stringRedisSerializer.serialize(StringUtils.toString(un)));
												map.put(AppCanstant.SmsEntity.Smcont, AppStaticConfigs.stringRedisSerializer.serialize(StringUtils.toString(body.getMsgContent())));
												map.put(AppCanstant.SmsEntity.Reportflag, AppStaticConfigs.stringRedisSerializer.serialize(StringUtils.toString(body.getReportFlag())));
												map.put(AppCanstant.SmsEntity.recvTime, AppStaticConfigs.stringRedisSerializer.serialize(StringUtils.toString(recvTime)));
												map.put(AppCanstant.SmsEntity.RecvModuleName, AppStaticConfigs.stringRedisSerializer.serialize(StringUtils.toString(smspfmModuleName)));
												map.put(AppCanstant.SmsEntity.SendPort, AppStaticConfigs.stringRedisSerializer.serialize(StringUtils.toString(body.getSendPort())));
												map.put(AppCanstant.SmsEntity.SerialSegment, AppStaticConfigs.stringRedisSerializer.serialize(StringUtils.toString(head.getSerialNoPart1() + "," + head.getSerialNoPart2() + "," + head.getSerialNoPart3())));
												map.put(AppCanstant.SmsEntity.respresult, AppStaticConfigs.stringRedisSerializer.serialize("0"));
												map.put(AppCanstant.SmsEntity.resptime, AppStaticConfigs.stringRedisSerializer.serialize(DateTimeUtils.dateToStr(new Date(), "yyyyMMddHHmmss")));
												
												String sequn = serialNo + ":" + un;
												
												connection.hMSet(AppStaticConfigs.stringRedisSerializer.serialize(iSMCacheHashPrefix + ":" + sequn), map);
												//connection.lPush(iSMCacheB, AppStaticConfigs.stringRedisSerializer.serialize(sequn));
												seqNums.add(AppStaticConfigs.stringRedisSerializer.serialize(sequn));
											}
											
											//connection.zAdd(AppStaticConfigs.iRptRecvSerialsZSetB, System.currentTimeMillis(), AppStaticConfigs.stringRedisSerializer.serialize(msg.getEncodeSerialNo()));
											
											serialnos.add(serialNo);
										}
										
										connection.lPush(iSMCacheB, seqNums.toArray(new byte[1][]));
									}
									
									@Override
									public void excuteCallback(List<Object> results) {
										logger.acceptd(serialnos.size() + " saved " + serialnos.toString());
									}
								});
							}
						});
					} else {
						try {
							TimeUnit.MILLISECONDS.sleep(100);
						} catch (InterruptedException e) {}
					}
				}
			}
		}).start();
	}
	
	@Override
	public void handleSubmitMessage(Head head, Submit body, ExtSocket socket) {
		
		executorService.execute(new Runnable() {
			
			@Override
			public void run() {
				
				MessageSbt message = new MessageSbt(head, body);
				
				logger.debug(message.toString());
				
				String srvNode = body.getSrvNode();
				String serviceCode = body.getServiceCode();
				String sendPort = body.getSendPort();
				
				if (isExtCodeUsable2(srvNode, sendPort)) { // 扩展码是否正确
					
					if (isSrvNodeService2(srvNode, serviceCode)) { // 业务端是否包含该业务类型
						
						boolean isForbidTime = false; // 是否属于禁发时段
						
						if (AppStaticConfigs.forbidtimeFilterOn) {
							isForbidTime = isForbidTime2(srvNode, serviceCode);
						}
						
						if (!isForbidTime) { 
							
							String encodeSerialNo = head.getSerialNo();
							
							boolean isRepeat = false; // 是否序号重复
							
							if (AppStaticConfigs.repeatseqsFilterOn) {
								isRepeat = filterQueue.contains(encodeSerialNo);
							}
							
							if (!isRepeat) {
								
								if (AppStaticConfigs.speedStatisticsOn) {
									increaseCurrSpeedS(1);
									increaseCurrSpeedM(1);
								}
								
								message.setRecvTime(new Date());
								message.setEncodeSerialNo(encodeSerialNo);
								
								sbt1Msg.put(message);
								
								logger.acceptd(message.toString());
								
								socket.response(message, ErrorCode.CODE0);
								
							} else {
								logger.rejectd("重复发送错:"+message.toString());
								socket.response(message, ErrorCode.CODE_2);
							}
						} else {
							logger.rejectd("禁发时段错:"+message.toString());
							socket.response(message, ErrorCode.CODE_1);
						}
					} else {
						logger.rejectd("业务类型不匹配:"+message.toString());
						socket.response(message, ErrorCode.CODE_7);
					}
				} else {
					logger.rejectd("扩展码不匹配:"+message.toString());
					socket.response(message, ErrorCode.CODE_8);
				}
			}
		});
	}

	@Override
	public void handleSubmit2Message(Head head, Submit2 body, ExtSocket socket) {
		
		executorService.execute(new Runnable() {
			
			@Override
			public void run() {
				
				MessageSbt message = new MessageSbt(head, body);
				
				logger.debug(message.toString());
				
				String srvNode = body.getSrvNode();
				String serviceCode = body.getServiceCode();
				//String sendPort = StringUtils.substring(body.getSendPort(), 5);
				
				if (isSrvNodeService2(srvNode, serviceCode)) {
					
					boolean isForbidTime = false; // 是否属于禁发时段
					
					if (AppStaticConfigs.forbidtimeFilterOn) {
						isForbidTime = isForbidTime2(srvNode, serviceCode);
					}
					
					if (!isForbidTime) {
						
						String encodeSerialNo = MD5Util.encode(body.getOrgSerialNo());
						
						boolean isRepeat = false; // 是否序号重复
						
						if (AppStaticConfigs.repeatseqsFilterOn) {
							isRepeat = filterQueue.contains(encodeSerialNo);
						}
						
						if (!isRepeat) {
							
							if (AppStaticConfigs.speedStatisticsOn) {
								increaseCurrSpeedS(1);
								increaseCurrSpeedM(1);
							}
							
							message.setRecvTime(new Date());
							message.setEncodeSerialNo(encodeSerialNo);
							
							sbt2Msg.put(message);
							
							logger.acceptd(message.toString());
							
							socket.response(message, ErrorCode.CODE0);
							
						} else {
							logger.rejectd("重复发送错:"+message.toString());
							socket.response(message, ErrorCode.CODE_2);
						}
					} else {
						logger.rejectd("禁发时段错:"+message.toString());
						socket.response(message, ErrorCode.CODE_1);
					}
				} else {
					logger.rejectd("业务类型不匹配:"+message.toString());
					socket.response(message, ErrorCode.CODE_7);
				}
			}
		});
	}
	
	/**
	 * 是否在禁发时间段内
	 * @param srvNode
	 * @param serviceCode
	 * @return
	 */
	private final boolean isForbidTime2(String srvNode, String serviceCode) {
		
		boolean result = false;
		
		Set<String> set = new HashSet<>(); // 所有适用的规则
		
		String ssrvNode = StringUtils.toString(srvNode);
		String sserviceCode = StringUtils.toString(serviceCode);
		
		Set<String> set2 = AppStaticConfigs.forbidTimeMap.get(ssrvNode + ":" + sserviceCode);
		if (set2 != null) {
			set.addAll(set2); // 针对指定业务端的指定业务类型
		}
		Set<String> set3 = AppStaticConfigs.forbidTimeMap.get(ssrvNode + ":");
		if (set3 != null) {
			set.addAll(set3);// 针对指定业务端的所有业务
		}
		Set<String> set4 = AppStaticConfigs.forbidTimeMap.get(":" + sserviceCode);
		if (set4 != null) {
			set.addAll(set4); // 针对制定业务类型的所有客户端
		}
		Set<String> set5 = AppStaticConfigs.forbidTimeMap.get(":");
		if (set5 != null) {
			set.addAll(set5); // 针对所有业务端的所有类型
		}
		
		List<String> forbidTime = null;
		for (String str:set) {
			if (StringUtils.isEmpty(str)) continue;
			String[] strings = str.split(":");
			float startTime = StringUtils.strToFlaot(StringUtils.toString(strings[0]));
			float endTime = StringUtils.strToFlaot(StringUtils.toString(strings[1]));
			if (DateTimeUtils.isInInterval(startTime, endTime)) {
				//序列号：手机号码: start-end,start-end
				if (forbidTime == null) {
					forbidTime = new ArrayList<>();
				}
				forbidTime.add(startTime + "-" + endTime);
			}
		}
		
		if (forbidTime != null) {
			result = true;
		}
		
		return result;
	}
	
	/**
	 * 判断SrvNode中是否包含业务类型ServiceCode
	 * @param srvNode
	 * @param serviceCode
	 * @return
	 */
	private final boolean isSrvNodeService2(String srvNode, String serviceCode) {
		boolean result = false;
		
		Set<String> serviceCodes = AppStaticConfigs.srvNSCodeMap.get(srvNode);
		
		if (serviceCodes != null && serviceCodes.contains(serviceCode)) {
			result = true;
		}
		
		return result;
	}
	
	/**
	 * 判断扩展码是否可用
	 * @param srvNode
	 * @param sendPort
	 * @return
	 */
	private final boolean isExtCodeUsable2(String srvNode, String sendPort) {
		
		boolean result = false;
		
		Set<String> extCodes = AppStaticConfigs.srvNodeExtCodeMap.get(srvNode);
		
		if (extCodes != null) {
			for (String ec:extCodes) {
				if (StringUtils.startsWith(sendPort, ec)) {
					result = true;
					break;
				}
			}
		}
		
		return result;
	}
	
	private final void startUpdateSpeedTasks() {
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				while(executorService != null && !executorService.isShutdown()) {
					
					long speed = getAndResetCurrSpeedS();
					
					speeds.offer(Collections.singletonMap(CURR_ACCEPT_SPEEDS_B, AppStaticConfigs.stringRedisSerializer.serialize(speed + ":" + DateTimeUtils.dateToStr2(null))));
					
					logger.debug("接口接收速度(条/s):" + speed);
					
					try {
						TimeUnit.MILLISECONDS.sleep(1000);
					} catch (InterruptedException e) {}
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				int count = 0;
				
				while(executorService != null && !executorService.isShutdown()) {
					
					if (count >= 60) {
						
						long speed = getAndResetCurrSpeedM();
						
						speeds.offer(Collections.singletonMap(CURR_ACCEPT_SPEEDM_B, AppStaticConfigs.stringRedisSerializer.serialize(speed + ":" + DateTimeUtils.dateToStr2(null))));
						
						logger.debug("接口接收速度(条/m):" + speed);
						
						count = 0;
						
					} else {
						count ++;
					}
					
					try {
						TimeUnit.MILLISECONDS.sleep(1000);
					} catch (InterruptedException e) {}
				}
			}
		}).start();
	}
	
	private final void startSpeedWriteTasks() {
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				while (executorService != null && !executorService.isShutdown()) {
					
					Map<byte[],byte[]> map = speeds.poll();
					if (map != null && !map.isEmpty()) {
						AppStaticConfigs.pipelineOpts.save(new ABExcuteCommands() {

							@Override
							public void excute(RedisConnection connection) {
								connection.hMSet(AppStaticConfigs.RunningParamsHashB, map);
								// 每秒的速率队列
								byte[] bytes = map.get(CURR_ACCEPT_SPEEDS_B);
								if (bytes != null) {
									connection.lPush(currAcceptSpeedS_List, bytes); 
									connection.lTrim(currAcceptSpeedS_List, 0, AppStaticConfigs.speedSLength - 1);
								}
								// 每分的速率队列
								byte[] bytem = map.get(CURR_ACCEPT_SPEEDM_B);
								if (bytem != null) {
									connection.lPush(currAcceptSpeedM_List, bytem); 
									connection.lTrim(currAcceptSpeedM_List, 0, AppStaticConfigs.speedMLength - 1);
								}
							}

							@Override
							public void excuteFailCallback() {
								// TODO Auto-generated method stub
								
							}
						});
					} else {
						try {
							TimeUnit.MILLISECONDS.sleep(1000);
						} catch (InterruptedException e) {}
					}
				}
			}
		}).start();
	}

	@Override
	public final void destroy() {
		
		super.destroy();
		
		if (executorService != null && !executorService.isShutdown()) {
			executorService.shutdown();
		}
		
		while (!executorService.isShutdown()) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {}
		}
		
		if (executorService != null && executorService.isShutdown()) {
			executorService = null;
		}
		
		while (sbt1Msg.getSize() > 0 || sbt2Msg.getSize() > 0) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {}
		}
		
		if (executorSaveService != null && !executorSaveService.isShutdown()) {
			executorSaveService.shutdownNow();
		}
		
		if (sbt1Msg != null) {
			sbt1Msg.destroy();
		}
		
		if (sbt2Msg != null) {
			sbt2Msg.destroy();
		}
	}
	
	private final long getAndResetCurrSpeedS() {
		long result = 0;
		synchronized (slock) {
			result = currSpeedS;
			currSpeedS = 0;
		}
		return result;
	}

	private final void increaseCurrSpeedS(long count) {
		synchronized (slock) {
			this.currSpeedS += count;
		}
	}

	public final long getCurrSpeedM() {
		return currSpeedM;
	}
	
	private final long getAndResetCurrSpeedM() {
		long result = 0;
		synchronized (mlock) {
			result = currSpeedM;
			currSpeedM = 0;
		}
		return result;
	}

	private final void increaseCurrSpeedM(long count) {
		synchronized (mlock) {
			this.currSpeedM += count;
		}
	}
}
